package org.example.camundaapp.service;

import lombok.extern.slf4j.Slf4j;
import org.camunda.bpm.engine.*;
import org.camunda.bpm.engine.history.HistoricActivityInstance;
import org.camunda.bpm.engine.history.HistoricProcessInstance;
import org.camunda.bpm.engine.history.HistoricTaskInstance;
import org.camunda.bpm.engine.repository.ProcessDefinition;
import org.camunda.bpm.engine.runtime.ProcessInstance;
import org.camunda.bpm.engine.task.Comment;
import org.camunda.bpm.engine.task.DelegationState;
import org.camunda.bpm.engine.task.Task;
import org.camunda.bpm.engine.task.TaskQuery;
import org.camunda.bpm.engine.variable.Variables;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 流程引擎服务
 * @className: CamundaEngineService
 * @author: ZHRJ
 * @date: 2025-06-26 11:28
 * @Version: 1.0
 * @description:
 */
@Slf4j
@Service
public class CamundaEngineService {

    private final RuntimeService runtimeService; // = ProcessEngines.getDefaultProcessEngine().getRuntimeService();
    private final TaskService taskService;
    private final HistoryService historyService;
    private final RepositoryService repositoryService;

    @Autowired
    public CamundaEngineService(RuntimeService runtimeService,
                                TaskService taskService,
                                HistoryService historyService,
                                RepositoryService repositoryService) {
        this.runtimeService = runtimeService;
        this.taskService = taskService;
        this.historyService = historyService;
        this.repositoryService = repositoryService;
    }

    /**
     * 启动流程实例
     * @param processKey 流程定义的key
     * @param variables 流程变量
     * @return 流程实例
     */
    public ProcessInstance startProcessInstance(String processKey, Map<String, Object> variables) {
        return runtimeService.startProcessInstanceByKey(processKey,variables);
    }

    /**
     * 启动流程
     * @param processDefinitionKey
     * @return
     */
    public ProcessInstance startProcess(String processDefinitionKey) {
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        RuntimeService runtimeService = processEngine.getRuntimeService();
        return runtimeService.startProcessInstanceByKey(processDefinitionKey);
    }

    /**
     * 启动流程实例 (推荐)
     * @param processDefinitionKey 流程定义 key
     * @param businessKey 业务 key
     * @param variables 流程变量
     * @return
     */
    public ProcessInstance startProcessInstance(String processDefinitionKey, String businessKey, Map<String, Object> variables) {
        return runtimeService.startProcessInstanceByKey(processDefinitionKey, businessKey, variables);
    }


    /**
     * 获取用户任务列表 （推荐）
     * @param userId 用户ID
     * @param processInstanceId 流程实例ID
     * @return
     */
    public List<Task> getPendingTasks(String userId, String processInstanceId) {
        TaskQuery query = taskService.createTaskQuery()
                .taskAssignee(userId)
                .active(); // 只查询活跃的待办任务

        if (processInstanceId != null && !processInstanceId.isEmpty()) {
            query.processInstanceId(processInstanceId);
        }

        List<Task> tasks = query.list();

       return tasks;
    }

    /**
     * 获取用户任务列表（通过受让人）
     * @param assignee 任务受让人 assignee=${}
     * @return 用户任务列表
     */
    public List<Task> getUserTasksByAssignee(String assignee) {
        return taskService.createTaskQuery()
                .taskAssignee(assignee)
                .orderByTaskCreateTime().desc()
                .list();
    }
    /**
     * 查询用户任务列表（通过实例ID）
     * @param instanceId 流程实例ID
     * @return 任务列表
     */
    public List<Task> queryTasksByInstanceId(String instanceId) {
        return taskService.createTaskQuery()
                .processInstanceId(instanceId)
                .list();
    }
    /**
     * 查询用户任务列表（通过发起人标识）
     * @param initiator 流程发起人ID
     * @return 任务列表
     */
    /**
     * 通过流程变量获取用户任务列表
     * @param variableName 流程变量名称 (bpmn中定义的assignee="${initiator}",变量就是initiator)
     * @param variableValue 流程变量值
     * @return
     */
    public List<Task> queryTasksByInitiator(String variableName ,String variableValue) {
        return taskService.createTaskQuery()
                .processVariableValueEquals(variableName, variableValue)
                .list();
    }

    // 通过任务名称或任务状态获取用户任务列表
    public List<Task> getUserTasks(String userId, String taskName, DelegationState taskStatus) {
        return taskService.createTaskQuery()
                .taskAssignee(userId)
                .taskDelegationState(taskStatus)
                .taskName(taskName)
                .orderByTaskCreateTime().desc()
                .list();
    }

    /**
     * 完成任务（不等于完成整个流程）
     * @param taskId  任务ID
     * @param variables 流程变量
     */
    public void completeTask(String taskId, Map<String, Object> variables) {
        taskService.complete(taskId,variables);
    }

    /**
     * 完成审批任务 （推荐）
     * @param taskId 任务 ID
     * @param approver 审批人
     * @param decision 审批决定
     * @param comment 审批意见
     * @param variables 流程变量
     */
    public void completeApprovalTask(String taskId, String approver, String decision, String comment, Map<String, Object> variables) {

        this.approvalTaskCheck(taskId, approver);

        // 设置任务受让人
        //taskService.setAssignee(taskId, approver);
        // 添加审批意见
        Comment taskComment = taskService.createComment(taskId, null, comment);
        //taskService.addComment(taskId, null, comment);
        log.info("任务ID：{}，全部审批意见：{}", taskId, taskComment.getFullMessage());
        // 将审批决定添加到流程变量中
        if (variables == null) {
            variables = new HashMap<>();
        }
        variables.put("decision", decision); // 审批结果：通过、拒绝
        variables.put("comment", comment); // 审批意见

        // 完成任务
        taskService.complete(taskId, variables);
    }

    /**
     * 完成审批校验
     * @param taskId
     * @param userId
     */
    public void approvalTaskCheck(String taskId, String userId) {

        // 查询任务
        Task task = taskService.createTaskQuery()
                .taskId(taskId)
                .singleResult();

        if (task == null) {
            throw new RuntimeException("任务 ID " + taskId + " 不存在");
        }

        // 检查审批人是否为任务受让人
        if (userId.equals(task.getAssignee())) {
            // 审批人是任务受让人，直接继续审批
        } else {
            // 检查审批人是否为候选人
            long candidateCount = taskService.createTaskQuery()
                    .taskId(taskId)
                    .taskCandidateUser(userId)
                    .count();

            if (candidateCount > 0) {
                // 审批人是候选人，尝试认领任务
                //taskService.claim(taskId, userId);
                throw new RuntimeException("用户 " + userId + " 属于候选人，需要先认领才能完成该任务");
            } else {
                // 审批人既不是受让人也不是候选人，不允许审批
                throw new RuntimeException("用户 " + userId + " 不是任务 " + taskId + " 的受让人或候选人，不能完成该任务");
            }
        }


    }


    // 获取流程图形
    public byte[] getProcessDiagram(String processInstanceId) {
        try{
            // 获取流程定义
            ProcessInstance processInstance = runtimeService.createProcessInstanceQuery()
                    .processInstanceId(processInstanceId)
                    .singleResult();
            if(null == processInstance){
                throw new RuntimeException("流程实例不存在");
            }
            // 获取流程定义
            ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery()
                    .processDefinitionId(processInstance.getProcessDefinitionId())
                    .singleResult();

            if (processDefinition == null) {
                throw new RuntimeException("未找到流程定义: " + processInstanceId);
            }

            // 获取流程图的资源名称
            String diagramResourceName = processDefinition.getDiagramResourceName();
            if (diagramResourceName == null) {
                throw new RuntimeException("未找到流程定义的图表资源: "
                        + processDefinition.getId());
            }

            // 获取流程图输入流
            InputStream inputStream = repositoryService.getResourceAsStream(
                    processDefinition.getDeploymentId(),
                    diagramResourceName);

            if (inputStream == null) {
                throw new RuntimeException("无法获取图表资源输入流: "
                        + diagramResourceName);
            }

            // 转换为字节数组
            ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
            byte[] buffer = new byte[1024];
            int length;
            while ((length = inputStream.read(buffer)) != -1) {
                outputStream.write(buffer, 0, length);
            }

            return outputStream.toByteArray();

        }catch (Exception e){
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 获取流程历史
     * @param processInstanceId 流程实例ID
     * @return 流程历史列表
     */
    public List<HistoricActivityInstance> getProcessHistory(String processInstanceId) {
        return historyService.createHistoricActivityInstanceQuery()
                .processInstanceId(processInstanceId)
                .orderByHistoricActivityInstanceStartTime().asc()
                .list();
    }

    /**
     * 获取审批历史流程
     * @param processInstanceId 流程实例ID
     * @return 审批历史流程列表
     */
    public List<HistoricTaskInstance> getTaskHistory(String processInstanceId) {
        return historyService.createHistoricTaskInstanceQuery()
                .processInstanceId(processInstanceId)
                .finished()
                .list();
    }

    // 挂起流程
    public void suspendProcess(String processInstanceId) {
        runtimeService.suspendProcessInstanceById(processInstanceId);
    }
    // 激活流程
    public void activateProcess(String instanceId) {
        runtimeService.activateProcessInstanceById(instanceId);
    }
    // 删除流程实例
    public void deleteProcess(String instanceId, String reason) {
        runtimeService.deleteProcessInstance(instanceId, reason);
    }

    // 任务自由跳转
    public void jumpTask(String currentTaskId, String targetNodeId) {
        taskService.complete(currentTaskId,
                Variables.createVariables().putValue("targetNodeId", targetNodeId)
        );
    }
    // 多人并行审批任务查询
    public List<Task> getParallelTasks(String processInstanceId,String assignee) {
         return taskService.createTaskQuery()
                .processInstanceId(processInstanceId)
                .initializeFormKeys() // 支持表单变量[7](@ref)
                 //.taskAssignee(assignee)
                 .list();
    }


    /**
     * 获取流程状态
     * @param processInstanceId
     * @return 流程状态：RUNNING-运行, SUSPENDED-暂停, COMPLETED-完成, NOT_FOUND-未找到
     */
    public String getProcessStatus(String processInstanceId) {
        // 检查流程是否正在运行
        boolean isRunning = runtimeService.createProcessInstanceQuery()
                .processInstanceId(processInstanceId)
                .active()
                .count() > 0;

        if (isRunning) {
            // 检查流程是否被挂起
            boolean isSuspended = runtimeService.createProcessInstanceQuery()
                    .processInstanceId(processInstanceId)
                    .suspended()
                    .count() > 0;
            return isSuspended ? "SUSPENDED" : "RUNNING";
        } else {
            // 检查流程是否已结束
            HistoricProcessInstance historicProcessInstance = historyService.createHistoricProcessInstanceQuery()
                    .processInstanceId(processInstanceId)
                    .singleResult();
            return historicProcessInstance != null ? "COMPLETED" : "NOT_FOUND";
        }
    }

    /**
     * 认领任务
     * @param taskId
     * @param assignee
     */
    public void claimTask(String taskId, String assignee) {
        taskService.claim(taskId, assignee);
    }

    // 查询任务信息
    public Task queryTaskById(String taskId) {
        return taskService.createTaskQuery()
               .taskId(taskId)
               .singleResult();
    }

    /**
     * 动态添加候选人
     * @param taskId
     * @param userId
     */
    public void addCandidateUser(String taskId, String userId) {
        taskService.addCandidateUser(taskId, userId);
    }

    /**
     * 候选人查询任务列表
     * @param userId 候选人ID
     * @return
     */
    public List<Task> getCandidateTasks(String userId) {
        return taskService.createTaskQuery()
                .taskCandidateUser(userId)
                .list();
    }
}
